import pygame.draw

import util.Location
from game.RenderManager import *
from game import RenderManager as rm, SokobanBox
from game import LevelManager as lm
from game import TextureManager as tm


class Component:
    def __init__(self, x: int, y: int, width: int, height: int):
        self.x = x
        self.y = y
        self.width = width
        self.height = height
        self.dic = {}  # 用于外部存储特殊数据

    def render(self, screen=rm.screen):
        pass

    def on_mouse_up(self, button: int, pos: tuple[int, int], deviation_x=0, deviation_y=0):
        pass

    def on_key(self, keys):
        pass

    def on_mouse_move(self, x: int, y: int):
        pass

    def set_pos(self, x: int, y: int):
        self.x = x
        self.y = y


class GUI:
    components = []
    def __init__(self, name: str):
        self.name = name


    def init(self):
        pass

    def render(self, on_screen=rm.screen):
        for component in self.components:
            component.render(on_screen)

    def add_component(self, component: Component):
        self.components.append(component)

    def on_mouse_up(self, button: int, pos: tuple[int, int], deviation_x=0, deviation_y=0):
        for component in self.components:
            component.on_mouse_up(button, pos,deviation_x,deviation_y)

    def on_key(self, keys):
        for component in self.components:
            component.on_key(keys)

    def on_mouse_move(self, x: int, y: int):
        for component in self.components:
            component.on_mouse_move(x, y)

    def close(self):
        self.components.clear()


class Button(Component):
    def __init__(self, id, title: str, x: int, y: int, width: int, height: int, onClick):
        super().__init__(x, y, width, height)
        self.id = id
        self.title = title
        self.onClick = onClick
        self.render_func = None
        self.mouse_move_func = None

    def render(self, on_screen=rm.screen):
        if not self.render_func is None:
            self.render_func(self, on_screen)

    def on_mouse_up(self, button: int, pos: tuple[int, int], deviation_x=0, deviation_y=0):
        x, y = pos
        if button == 1:  # 左键
            if util.Location.in_box(x, y, self.x+deviation_x, self.y+deviation_y,
                                    self.width, self.height):
                self.onClick(self)

    def on_mouse_move(self, x: int, y: int):
        if self.mouse_move_func is None:
            return
        if util.Location.in_box(x, y, self.x, self.y,
                                self.width, self.height):
            self.mouse_move_func(x, y, self)


class ComponentList(Component):
    def __init__(self, x: int, y: int, width: int, height: int, member_x: int, member_y: int, interval: int,
                 scroll_direction: str):
        super().__init__(x, y, width, height)
        self.member_x = member_x
        self.member_y = member_y
        self.interval = interval
        self.scroll_direction = scroll_direction
        self.scroll = 0
        self.target_scroll = 0
        self.speed = 0
        self.surface = pygame.surface.Surface([width, height]).convert_alpha()
        self.components = []
        self.total_width = 0
        self.member_width = 0

    def render(self, on_screen=rm.screen):
        self.surface.fill((0, 0, 0, 0))
        i = 0
        self.scroll += self.speed
        self.speed *= 0.87
        if self.scroll < -abs(self.target_scroll):
            self.scroll = -abs(self.target_scroll)
        if self.scroll > 0:
            self.scroll = 0

        for component in self.components:
            component.set_pos(self.member_x + (self.scroll_direction == "x") * i * (self.interval + component.width) + (
                    self.scroll_direction == "x") * self.scroll,
                              self.member_y + (self.scroll_direction == "y") * i * (
                                      self.interval + component.height) + (
                                      self.scroll_direction == "y") * self.scroll)
            if "rect" in component.dic:
                component.dic["rect"].x = component.x
                component.dic["rect"].y = component.y

            component.render(self.surface)
            i += 1
        on_screen.blit(self.surface, [self.x, self.y], self.surface.get_rect())

    def add_component(self, component: Component):
        self.components.append(component)
        self.total_width += component.width + self.interval
        self.member_width = component.width

    def on_mouse_up(self, button: int, pos: tuple[int, int], deviation_x=0, deviation_y=0):
        if button == 4:
            self.speed += 10
        elif button == 5:
            self.speed -= 10
        self.target_scroll = -(abs(self.total_width - (self.interval + self.member_width) * 3))
        for component in self.components:
            component.on_mouse_up(button, pos,self.x,self.y)


class MainMenu(GUI):
    def __init__(self):
        super().__init__("MainMenu")

    def button_on_click(self, button: Button):
        if button.id == 0:
            log.debug("button_start pressed!")
            SokobanBox.display(LevelChooseGUI())

            # SokobanBox.play_level(lm.get_level("test_level"))

        elif button.id == 1:
            log.debug("button_setting pressed!")
        elif button.id == 2:
            log.debug("button_quit pressed!")
            SokobanBox.quit()

    def button_render(self, button: Button, screen=rm.screen):
        x = button.x / 16 / rm.config.scale
        y = button.y / 16 / rm.config.scale
        width = button.width / 16 / rm.config.scale - 1
        height = button.height / 16 / rm.config.scale - 2
        title = button.title
        id = button.id
        draw_boxes(x, y, x + width, y + height)

        width_screen, height_screen = get_screen_size()
        text_size = get_string_size(title, 24 * config.scale)
        draw_string(title, int((width_screen - text_size[0]) / 2),
                    7 * 16 * config.scale + id * (4 * 16 * config.scale) + (2 * 16 * config.scale - text_size[1]) / 2,
                    "white",
                    24 * config.scale)

        if button.dic.get("focus", False):  # 喷泉
            draw("overworld", "fountain", 1, button.y)
            draw("overworld", "fountain", 16, button.y)

    def init(self):
        start_button = Button(0, "s t a r t", 5 * 16 * config.scale, 7 * 16 * config.scale, 10 * 16 * config.scale,
                              3 * 16 * config.scale, self.button_on_click)
        start_button.render_func = self.button_render
        self.add_component(start_button)

        setting_button = Button(1, "s e t t i n g", 5 * 16 * config.scale, 11 * 16 * config.scale,
                                10 * 16 * config.scale, 3 * 16 * config.scale, self.button_on_click)
        setting_button.render_func = self.button_render
        self.add_component(setting_button)

        quit_button = Button(2, "q u i t", 5 * 16 * config.scale, 15 * 16 * config.scale, 10 * 16 * config.scale,
                             3 * 16 * config.scale, self.button_on_click)
        quit_button.render_func = self.button_render
        self.add_component(quit_button)

    def render(self, screen=rm.screen):
        for i in range(20):
            for j in range(20):
                draw("overworld", "grass", i, j)  # 草坪背景

        width_screen, height_screen = get_screen_size()  # 标题
        width_title, height_title = get_size("title", "title")
        draw("title", "title", (width_screen - width_title) / 2, int(height_screen / 9), False)

        super().render()  # 渲染控件

    def on_mouse_move(self, x: int, y: int):
        for component in self.components:  # 处理焦点
            component.dic["focus"] = util.Location.in_box(x, y, component.x * 16 * config.scale,
                                                          component.y * 16 * config.scale,
                                                          (component.width + 1) * 16 * config.scale,
                                                          (component.height + 2) * 16 * config.scale)


class LevelChooseGUI(GUI):
    def __init__(self):
        super().__init__("LevelChooseGUI")

    def button_on_click(self, button: Button):
        log.debug("level button pressed!")
        SokobanBox.play_level(lm.get_level(button.id))
        SokobanBox.display(None)

    def button_render(self, button: Button, on_screen=rm.screen):

        if not ("level" in button.dic and "rect" in button.dic):
            button.dic["level"] = lm.get_level(button.id)
            button.dic["rect"] = pygame.rect.Rect(button.x - 2, button.y - 2, button.width + 4, button.height + 4)

        pygame.draw.rect(on_screen, "white", button.dic["rect"])
        draw_level(button.dic["level"], config.scale / 16 * 5, button.x + 2, button.y + 2, on_screen=on_screen)
        draw_string(button.id, int(button.x + (button.width - get_string_size(button.id, 12 * config.scale)[0]) / 2),
                    button.y + button.height + 5, "white", 12 * config.scale,on_screen)

    def back_button_on_click(self, button: Button):
        pass
    def back_button_render(self,button: Button, on_screen=rm.screen):
        pass
    def init(self):
        w, h = get_screen_size()
        component_list = ComponentList(5, int(h / 6.4), rm.screen.get_width() - 10,
                                       int(h / 2), 5, int(rm.screen.get_height() / 10), int(h / 64), "x")
        self.add_component(component_list)

        for level_name in lm.levels.keys():
            button = Button(level_name, level_name, 0, 0, 100 * rm.config.scale, 100 * rm.config.scale,
                            self.button_on_click)
            button.render_func = self.button_render
            component_list.add_component(button)

    def render(self, on_screen=rm.screen):
        for i in range(20):
            for j in range(20):
                draw("overworld", "grass", i, j)  # 草坪背景
        super().render(on_screen)
